﻿
#include <iostream>
#include <iomanip>
#include <queue>
#include <string>
#include <vector>
#include <windows.h>            //Sleep()函数  system("cls");
using namespace std;
typedef struct process PCB;
typedef struct process
{
	string name;//进程名
	int inTime;
	int startTime; /*开始时间*/
	int totalTime;/*所需总服务时间*/
	int servedTime; /*已服务时间*/
	int needTime; /*进程到完成还要的时间*/
	int flag;
	vector<int> disp;
};
vector<PCB> proc;//存储进程的向量
vector<PCB> allV;//修改后的存储进程的向量
vector<int> rTimeOrder;
queue<PCB> runningQ;
queue<PCB> readyQ;
queue<PCB> finishQ;

int globalTimer = 0;//已经运行的时间
int qTimeSize;//时间片大小
int remainTime = 0;//一个时间片未使用完的剩余时间片
int index = 0;
int menu;
int x, y;//光标所在位置
//移动光标
void gotoxy(int x, int y) {
	COORD pos = { x,y };
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut, pos);
}

//获取光标位置
void getXY() {
	HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD coordScreen = { 0, 0 }; //光标位置
	CONSOLE_SCREEN_BUFFER_INFO csbi;

	if (GetConsoleScreenBufferInfo(hConsole, &csbi))
	{
		x = csbi.dwCursorPosition.X; y = csbi.dwCursorPosition.Y + 1;
	}

}

//按照进程的开始时间进行升序排列
bool cmpStartime(PCB& a, PCB& b) {
	return a.startTime < b.startTime;
}

//输出所有队列
void showT() {
	cout << setw(6) << "进程名"
		<< setw(12) << "已服务时间"
		<< setw(12) << "还需要时间"
		<< setw(12) << "时间片大小"
		<< setw(8) << "状态" << endl;
	queue<PCB> Q;
	Q = runningQ;//运行队列
	while (!Q.empty()) {
		cout << setw(2) << Q.front().name
			<< setw(12) << Q.front().servedTime
			<< setw(12) << Q.front().needTime
			<< setw(12) << qTimeSize
			<< setw(14) << "R(运行)" << endl;
		Q.pop();
	}
	Q = readyQ;//就绪队列
	while (!Q.empty()) {
		cout << setw(2) << Q.front().name
			<< setw(12) << Q.front().servedTime
			<< setw(12) << Q.front().needTime
			<< setw(12) << qTimeSize
			<< setw(14) << "W(就绪)" << endl;
		Q.pop();
	}
	Q = finishQ;//完成队列
	while (!Q.empty()) {
		cout << setw(2) << Q.front().name
			<< setw(12) << Q.front().servedTime
			<< setw(12) << Q.front().needTime
			<< setw(12) << qTimeSize
			<< setw(14) << "F(完成)" << endl;
		Q.pop();
	}
	getchar();
}

//图形显示
void show() {
	//cout << "■" << endl;
	//cout << "□" << endl;
	//打印时间片序列
	
	cout << setw(10) << "时间片序列" << " |";
	for (int i = 0; i < rTimeOrder.size(); i++) {
		cout << setw(rTimeOrder[i]*2) << i + 1 << "|";//<< setw(qTimeSize)
	}
	cout << setw(14) << "进程开始时间" << setw(14) << "要求服务时间" << setw(12) << "已服务时间" << setw(8) << "状态";
	cout << endl;
	
	
	//输出进程
	for (auto tmp : allV) {
		int tps = 0, numOfFinish = 0;
		cout << setw(8) << "进程名:"
			<< setw(2) << tmp.name << " |";
		if (tmp.flag)//如果在当前进程就打印绿色
			cout << "\033[32m";
		for (auto i : tmp.disp) {
			if (i == 2) {
				cout << "|";
			}
			else if (i==1) {
				numOfFinish++;
				cout << "■";
			}
			else {
				cout << "□";
			}
			tps++;
			//if (tps % qTimeSize == 0) cout << "|";
		}
		cout << setw(10) << tmp.inTime << setw(14) << tmp.totalTime << setw(12) << numOfFinish;
		if (tmp.flag == 1)cout << setw(14) << "R(运行)";
		else {
			if (numOfFinish == tmp.totalTime)
				cout << setw(14) << "F(完成)";
			else
				cout << setw(14) << "W(就绪)";
		}
		cout << "\033[0m" << endl;

	}
	cout << endl;
	getchar();
}

//输入进程
void inputProcess(int num) {
	PCB tmp;
	cout << "输入 进程名 进程开始时间 所需服务时间：\n";
	for (int i = 0; i < num; i++) {
		cin >> tmp.name >> tmp.inTime >> tmp.totalTime;
		tmp.startTime = tmp.inTime-1;
		tmp.servedTime = 0;
		tmp.needTime = tmp.totalTime - tmp.servedTime;
		proc.push_back(tmp);

	}
}

//时间片轮转
void roundRobin() {
	//按照进程的开始时间进行升序排列
	sort(proc.begin(), proc.end(), cmpStartime);

	//进程进入就绪队列
	for (auto pro : proc) {
		allV.push_back(pro);
		readyQ.push(pro);
	}

	getchar();
	if (menu == 0)
		showT();//查看初始状态

	while (finishQ.size() != proc.size()) {//进程没有完成就继续时间片轮转
		index++;
		if (menu == 0) cout << "\033[33m-----------------------第" << index << "个时间片" << "----------------------- \033[0m" << endl;
		remainTime = qTimeSize;
		int nowTime;
		nowTime = globalTimer;
		int preRR = 0;//上个切换的进程执行完了
		runningQ.push(readyQ.front());//将就绪队首入运行对列

		int st = 0;
		//判断进程是否开始
		if (runningQ.front().startTime <= nowTime) {//说明进程已经开始
			readyQ.pop();
			st = runningQ.front().servedTime + remainTime;//消耗时间片转为已服务时间
		}
		else if (runningQ.front().startTime > nowTime && runningQ.front().startTime <= globalTimer + qTimeSize) {//进程刚好在时间片中间开始,新开一个时间片
			globalTimer += runningQ.front().startTime - nowTime;
			rTimeOrder.push_back(runningQ.front().startTime - nowTime);
			//记录正在运行进程，白块,其余记录黑块
			for (int item = 0; item < allV.size(); item++) {
				for (int i = 0; i < runningQ.front().startTime - nowTime; i++) {
					allV[item].disp.push_back(0);
				}
				allV[item].disp.push_back(2);
			}
			runningQ.pop();//执行队列并未执行
			continue;

		}
		else {//进程在此时间片未开始
			globalTimer += qTimeSize;
			rTimeOrder.push_back(qTimeSize);
			//记录正在运行进程，白块,其余记录黑块
			for (int item = 0; item < allV.size(); item++) {
				for (int i = 0; i < qTimeSize; i++)
					allV[item].disp.push_back(0);
				allV[item].disp.push_back(2);
			}
			runningQ.pop();//执行队列并未执行
			continue;
		}
		//时间片不够用
		if (st < runningQ.front().totalTime) {
			//记录正在运行进程，白块,其余记录黑块
			for (int item = 0; item < allV.size(); item++) {
				if (allV[item].name == runningQ.front().name) {
					allV[item].flag = 1;
					for (int i = 0; i < remainTime; i++) {
						allV[item].disp.push_back(1);
					}
					allV[item].disp.push_back(2);
				}
				else {
					allV[item].flag = 0;
					for (int i = 0; i < remainTime; i++) {
						allV[item].disp.push_back(0);
					}
					allV[item].disp.push_back(2);
				}
			}
			if (menu == 0)showT();
			if (menu == 1) { gotoxy(x, y); show(); }
			remainTime = 0;
			runningQ.front().servedTime = st;//服务时间增加
			runningQ.front().needTime = runningQ.front().totalTime - st;//需要时间减少
			readyQ.push(runningQ.front());//放入到就绪队列继续等待执行
			runningQ.pop();//清空执行队列
		}
		//时间片刚好够用
		else if (st == runningQ.front().totalTime) {
			//记录正在运行进程，白块,其余记录黑块
			for (int item = 0; item < allV.size(); item++) {
				if (allV[item].name == runningQ.front().name) {
					allV[item].flag = 1;
					for (int i = 0; i < remainTime; i++) {
						allV[item].disp.push_back(1);
					}
					allV[item].disp.push_back(2);
				}
				else {
					allV[item].flag = 0;
					for (int i = 0; i < remainTime; i++) {
						allV[item].disp.push_back(0);
					}
					allV[item].disp.push_back(2);
				}
			}

			if (menu == 0)showT();//查看运行时的状态
			if (menu == 1) { gotoxy(x, y); show(); }
			remainTime = 0;
			runningQ.front().servedTime = st;//服务时间增加
			runningQ.front().needTime = runningQ.front().totalTime - st;//需要时间减少
			finishQ.push(runningQ.front());//放入到完成队列
			runningQ.pop();//清空执行队列
		}
		//时间片有剩余没用完,新开时间片
		else {
			int tmp = remainTime;
			remainTime = st - runningQ.front().totalTime;//剩余时间片                
			//记录正在运行进程，白块,其余记录黑块
			for (int item = 0; item < allV.size(); item++) {
				if (allV[item].name == runningQ.front().name) {
					allV[item].flag = 1;
					for (int i = 0; i < tmp - remainTime; i++) {
						allV[item].disp.push_back(1);
					}
					allV[item].disp.push_back(2);
				}
				else {
					allV[item].flag = 0;
					for (int i = 0; i < tmp - remainTime; i++) {
						allV[item].disp.push_back(0);
					}
					allV[item].disp.push_back(2);
				}
			}

			if (menu == 0)showT();
			if (menu == 1) { gotoxy(x, y); show(); }
			runningQ.front().servedTime = runningQ.front().totalTime;//服务时间增加
			runningQ.front().needTime = 0;//需要时间减少
			finishQ.push(runningQ.front());//放入到完成队列
			runningQ.pop();//清空执行队列
		}
		
		//结束运行
		if (finishQ.size() == proc.size()) {
			for (int item = 0; item < allV.size(); item++) {
				allV[item].flag = 0;
			}
		}
		globalTimer += qTimeSize - remainTime;
		rTimeOrder.push_back(qTimeSize - remainTime);

	}
	if (menu == 0)cout << "\033[33m----------------------------结束-----------------------------\033[0m\n" << endl;
	if (menu == 0) { showT(); show(); }
	if (menu == 1) { gotoxy(x, y); show(); }
}
int main()
{
	cout << "输入时间片大小:" << endl;
	cin >> qTimeSize;
	int num;//进程个数
	cout << "输入进程个数" << endl;
	cin >> num;

	//输入进程
	inputProcess(num);

	cout << "选择输出格式：0:时间片 1:图形动态显示" << endl;
	cin >> menu;

	getXY();
	//时间片轮转
	roundRobin();

	cout << "Hello World!\n";
}
/*
a 0 4
b 1 3
c 2 4
d 3 2
e 4 4

A 0 4
B 0 3
C 0 4
D 0 2
E 0 4


A 0 1
B 0 1
C 0 1
D 0 3

a 0 1
b 0 1
c 0 1
d 0 2

a 0 2
b 0 2
c 0 4
d 0 1

a 0 1
b 3 2
c 5 5
d 4 7

a 0 1
b 1 1
c 5 3
d 9 1
e 
*/